package com.itic.appbase.applications.files.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileLock;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.UUID;



import com.itic.appbase.framework.plugins.logger.Log;
import com.itic.appbase.framework.utils.DateHelper;
import com.itic.appbase.framework.utils.MD5Helper;
import com.itic.appbase.framework.utils.StringHelper;
import com.itic.appbase.framework.utils.configuration.PropertyHelper;


/** 
 * 文件操作工具类.
 * <p>Company: itic</p>
 * @author: zhaokechun
 * @date: 2015年5月7日 下午1:21:09
 * @version: V1.0  
 */
public class FileHelper extends org.apache.commons.io.FileUtils {

	private static final int BUFFER_SIZE = 50 * 1024;

	private static double KB = 1024.0;
	private static double MB = 1024.0 * 1024;
	private static double GB = 1024.0 * 1024 * 1024;
	private static double TB = 1024.0 * 1024 * 1024 * 1024;
	
	/**
	 * 拷贝文件.
	 * @param src 源文件
	 * @param dst 目的文件
	 */
	public static void copy(File src, File dst) {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
			out = new BufferedOutputStream(new FileOutputStream(dst),
					BUFFER_SIZE);
			byte[] buffer = new byte[BUFFER_SIZE];
			int len = 0;
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
			if (null != out) {
				try {
					out.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}
	
	
	/**
	 * 拷贝目录.
	 * @param srcDir 源目录
	 * @param dstDir 目标目录
	 * @param override 如果有重名是否覆盖
	 */
	public static void copyDir(File srcDir, File dstDir, boolean override) {

		if (srcDir == null || dstDir == null || !srcDir.exists()) {
			return;
		}
		if (!dstDir.exists()) {
			dstDir.mkdirs();
		}

		File[] files = srcDir.listFiles();

		for (File file : files) {
			File dstFile = new File(dstDir.getAbsolutePath() + "/"
					+ file.getName());
			if (file.isFile()) {
				FileHelper.copy(file, dstFile);
			}
			if (file.isDirectory()) {
				copyDir(file, dstFile, false);
			}
		}

	}

	public static void releaseFileLockQuietly(FileLock lock) {
		if (lock == null || !lock.isValid()) {
			return;
		}
		try {
			lock.release();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 文件内容比较，通过比较文件的md5摘要来判断文件内容是否一致.
	 * 
	 * @param src  源文件
	 * @param dest 目标文件
	 * @return 文件内容一样返回true,否则false
	 */
	public static boolean fileCompare(File src, File dest) {
		if (src == null || dest == null) {
			throw new IllegalArgumentException(
					"source file or dest file must be not null");
		}
		String srcFileMD5 = MD5Helper.fileMd5(src);
		String destFileMD5 = MD5Helper.fileMd5(dest);

		return srcFileMD5 == null ? destFileMD5 == null : srcFileMD5
				.equals(destFileMD5);
	}
	
	
	/**
	 * 读取文件内容.
	 * @param file 需要读取的文件
	 * @param encoding 编码格式
	 * @return 文件内容
	 */
	public static String toString(File file, String encoding) {
		try {
			if (StringHelper.isBlank(encoding)) {
				return readFileToString(file);
			}
			return readFileToString(file, encoding);
		} catch (Exception ex) {
			Log.error("读取文件出错", ex);
			return null;
		}
	}
	
	
	/**
	 * 读取文件内容.
	 * @see toString(File file, String encoding)
	 * @param file
	 * @return 读取的文件内容
	 */
	public static String toString(File file) {
		return toString(file, null);
	}

	/**
	 * 遍历某个文件目录下是否存在某个文件
	 * 
	 * @param dir 需要遍历的文件夹
	 * @param fileName 文件名
	 * @return 若存在给定的文件返回true，否则返回false
	 * @throws IOException
	 */
	public static Boolean isExistFile(String dir, String fileName)
			throws IOException {
		File file = new File(dir);
		File[] files = file.listFiles();
		if (files != null) {
			for (File f : files) {
				if (f.getName().equals(fileName)) {
					return true;
				}
			}
			return false;
		}
		return false;
	}

	public static Boolean isExistFile1(String dir, String fileName)
			throws IOException {
		File file = new File(dir);
		File[] files = file.listFiles();
		if (files != null) {
			for (File f : files) {
				if (f.isDirectory()) {
					File[] newFiles = f.listFiles();
					if (newFiles != null) {
						for (File ff : newFiles) {
							if (ff.getName().equals(fileName)) {
								return true;
							}
						}
					}
				} else if (f.isFile()) {
					if (f.getName().equals(fileName)) {
						return true;
					}
				}
			}
			return false;
		}
		return false;
	}

	public static String getFileSize(String filePath) {
		File file = new File(filePath);
		if (file.exists()) {
			return modifyByte(String.valueOf(file.length()));
		}
		return "";
	}

	/**
	 * 字节转换
	 */
	public static String modifyByte(String length) {
		DecimalFormat df = new DecimalFormat("#.00");//
		double len = Double.valueOf(length);// 将字符型转换为double型
		String result = null;
		if (len < 1024) {
			result = len + "B";
		} else if (len < MB) {
			result = df.format(len / KB) + "KB";
		} else if (len < GB) {
			result = df.format(len / MB) + "MB";
		} else if (len < TB) {
			result = df.format(len / GB) + "GB";
		} else {
			result = df.format(len / TB) + "TB";
		}
		return result;
	}
	/**
     * 删除文件
     * @param fileName
     * @return boolean
     */
    public static boolean delFile(String fileName) {
        boolean delFlag = false;
        try {
            String myFileName = fileName;
            File file = new File(myFileName);
            if(file.exists()){//文件存在
                delFlag = file.delete();
            }
        } catch (Exception e) {
            Log.error("删除文件操作出错", e);
        }
        return delFlag;
    }
    /**
     * 删除指定目录及下边的文件
     * @param folderPath
     * @return boolean
     */
    public static boolean delFolderAll(String folderPath) {
        boolean delFlag = true;
        try {
            File dir = new File(folderPath);
            File filelist[] = dir.listFiles();
            int listlen = filelist.length;
            for (int i = 0; i < listlen; i++) {
                if (filelist[i].isDirectory()) {
                    delFolderAll(filelist[i].getAbsolutePath());
                } else {
                    if (!filelist[i].delete()){//删除不成功
                        delFlag = false;
                        return false;
                    }
                }
            }
            if (!dir.delete()){// 删除当前目录
                delFlag = false;
                return false;
            }
        } catch (Exception e) {
            delFlag = false;
            e.printStackTrace();
        }
        return delFlag;
    }
	/**
     * 重命名
     * @param oldPath
     * @param newPath
     * @return boolean
     */
     public static boolean renameFile(String oldPath,String newPath){ 
         boolean renameFlag = true;
         try {
             if(!oldPath.equals(newPath)){//新的文件名和以前文件名不同时,才有必要进行重命名 
                 File oldfile=new File(oldPath); 
                 File newfile=new File(newPath); 
                 if(!oldfile.exists()){
                     return false;//重命名文件不存在
                 }
                 if(newfile.exists()){//若在该目录下已经有一个文件和新文件名相同，则不允许重命名 
                     return false;
                 }else{ 
                     boolean flag = oldfile.renameTo(newfile);
                     if(flag){//重命名成功
                         //更改文件修改时间
                         flag = newfile.setLastModified(new Date().getTime());
                     }
                     return flag; 
                 } 
             }
        } catch (Exception e) {
            renameFlag = false;
            Log.error("文件重命名出错", e);
        }
         return renameFlag;
    }
     /** 文件重命名 
      * @param path 文件目录 
      * @param oldname  原来的文件名 
      * @param newname 新文件名 
      * @return boolean
      */ 
      public static boolean renameFileByPath(String path,String oldname,String newname){ 
          boolean renameFlag = true;
          try {
              if(!oldname.equals(newname)){//新的文件名和以前文件名不同时,才有必要进行重命名 
                  File oldfile=new File(path+"/"+oldname); 
                  File newfile=new File(path+"/"+newname); 
                  if(!oldfile.exists()){
                      return false;//重命名文件不存在
                  }
                  if(newfile.exists()){//若在该目录下已经有一个文件和新文件名相同，则不允许重命名 
                      return false;
                  }else{ 
                      oldfile.renameTo(newfile); 
                      return true;
                  } 
              }
         } catch (Exception e) {
             renameFlag = false;
             Log.error("文件重命名出错", e);
         }
          return renameFlag;
     }
	/**
     * 
     * 获取上传文件的根目录
     * 格式:
     *  用户主目录/项目编号_fileupload(若未配置项目编号则为fileupload)
     * @return 
     */
    public static String getRootDir() {
    	String result = "";
    	String uploadPath = PropertyHelper.getString("app.upload.path");
        String userHome = System.getProperty("user.home");
        
        if (StringHelper.isNotBlank(uploadPath)) {
            userHome = uploadPath;
        }
        String projectName = PropertyHelper.getString("app.code");
        StringBuilder rootDir = new StringBuilder();
        rootDir.append(userHome).append("/")
               .append(projectName == null ? "" : (projectName+"_"))
               .append("fileupload").append("/");
        result = rootDir.toString();
        return result;
    }
    
    /**
     * 
     * 获取上传文件的根目录
     * 格式:
     *  用户主目录/项目编号_fileupload(若未配置项目编号则为fileupload)
     * @return 
     */
    public static String getRootDirPhp(){
    	String string = PropertyHelper.getString("app.upload.path");
   	    String projectName = PropertyHelper.getString("app.code");
        StringBuilder rootDir = new StringBuilder();
        rootDir.append(string)
               .append(projectName == null ? "" : (projectName+"_"))
               .append("fileupload").append("/");
      	return rootDir.toString();//"D://jindu//phpStudy//WWW//";
    }
    
    /**
     * 
     * 获取上传文件的根目录
     * 格式:
     *  用户主目录/项目编号_fileupload(若未配置项目编号则为fileupload)
     * @return 
     */
    public static String getDownloadPath(){
    	String string = PropertyHelper.getString("app.download.path");
   	    String projectName = PropertyHelper.getString("app.code");
        StringBuilder rootDir = new StringBuilder();
        rootDir.append(string)
               .append(projectName == null ? "" : (projectName+"_"))
               .append("fileupload").append("/");
      	return rootDir.toString();//"D://jindu//phpStudy//WWW//";
    }
    
	/**
     * 生成保存文件的子目录
     * <p>文件信息存库 :格式:模块名称/日期/文件名（MD5编码后）
     * <p>示例: t_demo_scxz/2015-05-08/0763f56c0fea58224a2d3a9a87180cfa.jpg 
     * </br>
     * <p>文件信息不存库 :格式:文件夹路径/文件名 
     * <p>示例: 6300000000000000000000001/wjsm.txt     
     * @param fileName
     * @param mTName
     * @return
     */
    public static String relativePath(String fileName,String mTName,boolean dbFlag) {
        StringBuilder subDir = new StringBuilder();
        if(dbFlag){//保存到数据库
            subDir.append(mTName).append("/")
            .append(DateHelper.getDate()).append("/")
            .append(UUID.randomUUID()).append(fileName.substring(fileName.lastIndexOf(".")));        
        }else{//选择文件夹，则文件路径为：文件夹路径+文件名
            subDir.append(mTName).append("/").append(fileName);//选择文件夹，则文件路径为：文件夹路径+文件名
        }
        return subDir.toString();
    }
}
